package org.example.c01函数式编程;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * <a href="https://blog.csdn.net/fzy629442466/article/details/84629422">java8 Lambda Stream collect Collectors 常用详细实例</a>
 * <a href="https://www.jb51.net/article/138519.htm">详解Java8 Collect收集Stream的方法</a>
 * <a href="https://blog.csdn.net/io_field/article/details/54971608">Java 8系列之Stream的强大工具Collector</a>
 *
 * <p>
 * 创建人：yuanwl <br>
 * 创建时间：2018年8月20日 下午12:19:03 <br>
 * <p>
 * 修改人： <br>
 * 修改时间： <br>
 * 修改备注： <br>
 * </p>
 */
public class s08StreamCollectTest {

    private List<Integer> li = Arrays.asList(1, 2, 3, 4, 5, 1);
    private List<String> ls = Arrays.asList("nihao", "hi", "hello", "welcome");

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private class People {
        private Integer id;
        private String name;
        private Integer age;
    }

    List<People> list = Arrays.asList(new People(1, "A", 18),
            new People(2, "B", 19), new People(1, "C", 20));

    @Test
    public void simple() {
        Set<Integer> si = li.stream().collect(Collectors.toSet());
        System.err.println(si);

        Collection<Integer> ci = li.stream().collect(Collectors.toCollection(ArrayList::new));
        System.err.println(ci);
        Collection<Integer> ci2 = li.stream().collect(Collectors.toCollection(HashSet::new));
        System.err.println(ci2);

        Long count = li.stream().collect(Collectors.counting());
        System.err.println(count);
        System.err.println(li.stream().count()); //等价于上面, 更简洁
    }

    @Test
    public void statistics() {
        IntSummaryStatistics statistics = li.stream().collect(Collectors.summarizingInt(i -> i));
        System.err.println(statistics.getMax());
        System.err.println(statistics.getMin());
        System.err.println(statistics.getAverage());
        System.err.println(statistics.getSum());
        System.err.println(statistics.getCount());

        //等价于上面
        IntSummaryStatistics statistics2 = li.stream().mapToInt(i -> i).summaryStatistics();
        System.err.println(statistics2.getMax());
        System.err.println(statistics2.getMin());
        System.err.println(statistics2.getAverage());
        System.err.println(statistics2.getSum());
        System.err.println(statistics2.getCount());
    }

    @Test
    public void toMap() {
        Map<Integer, People> map = list.stream().collect(Collectors.toMap(People::getId, v -> v,
                (v1, v2) -> { //当 map 里存在相同的 key 时, v1 代表已存在的 value, v2 代表当前遍历的 value
                    System.err.println(v1 + "," + v2);
                    return v2; //返回的 value 作为最终保存到 map 的 value
                }));
        System.err.println(map);
    }

    @Test
    public void toMapNull() {
//		Map<Integer, People> map = list.stream().collect(Collectors.toMap(People::getId, i -> null, (v1, v2) -> v1)); //这样写会报错, 不允许value为null

        Map<Integer, People> map = list.stream().collect(HashMap::new, (r, t) -> r.put(t.getId(), null), (r1, r2) -> r1.putAll(r2));
		System.err.println(map);
    }

    @Test //Comparator: https://blog.csdn.net/lengguoxing/article/details/78415024
    public void comparator() {
        Optional<Integer> max = li.stream().collect(Collectors.maxBy(
                Comparator.comparingInt(i -> i) //comparing 和 comparingInt 效果一样
        ));
        max.ifPresent(System.err::println);

        //升序排序，流的写法
//		System.err.println(ls.stream().sorted(Comparator.comparing(str -> str))
//				.collect(Collectors.joining(",")));

        //升序排序，默认写法
//		Collections.sort(ls);
//		System.out.println("ls = " + ls);

        //自定义排序器,默认写法
//        Collections.sort(ls, (s1, s2) -> s1.compareTo(s2)); //升序
//        Collections.sort(ls, (s1, s2) -> s2.compareTo(s1));   //降序
//        System.out.println("ls = " + ls);

//		//自定义排序器,Comparator写法
        Collections.sort(ls, Comparator.comparingInt(str -> str.length()));                       //升序
//        Collections.sort(ls, Comparator.comparingInt(str -> str.length()).reversed());              //降序,会报错，因为编译器在这里无法推断str的类型为String，而是推断出事一个Objcet
        Collections.sort(ls, Comparator.comparingInt((String str) -> str.length()).reversed());   //降序,显示的指定一个类型
//
//		//自定义排序器,Comparator写法2
//        Collections.sort(ls, Comparator.comparingInt(String::length));           //升序
//        Collections.sort(ls, Comparator.comparingInt(String::length).reversed());  //降序
//        System.out.println("ls = " + ls);
//
//		//直接调用list的排序方法，Collections.sort()本质还是调用list.sort方法
//        ls.sort(Comparator.comparingInt(String::length));             //升序
//        ls.sort(Comparator.comparingInt(String::length).reversed());    //降序
//
//		/**两层排序:先按照长度排序，再按照字符串顺序**/
//		Collections.sort(ls, Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER));   //不区分大小写的排序
//		Collections.sort(ls, Comparator.comparingInt(String::length).thenComparing(String::compareTo));
//		Collections.sort(ls, Comparator.comparingInt(String::length).thenComparing((item1, item2) -> item1.toLowerCase().compareTo(item2.toLowerCase())));
//		Collections.sort(ls, Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase)));
//		Collections.sort(ls, Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder())));
//		Collections.sort(ls, Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder())).
//				thenComparing(Comparator.reverseOrder()));//和上一个结果是一样的，因为已经排好序了，最后一个就不起作用了
//		System.out.println("ls = " + ls);
    }

    @Test
    public void groupingBy() {
        Map<Integer, List<People>> map = list.stream().collect(Collectors.groupingBy(People::getId));
        System.err.println(map);

        Map<Integer, Long> map1 = list.stream().collect(Collectors.groupingBy(People::getId,
                Collectors.counting()));
        System.err.println(map1);

        Map<Integer, Integer> map2 = list.stream().collect(Collectors.groupingBy(People::getId,
                Collectors.summingInt(People::getAge)));
        System.err.println(map2);

        Map<Integer, Optional<People>> map3 = list.stream().collect(Collectors.groupingBy(People::getId,
                Collectors.maxBy(Comparator.comparing(People::getAge))));
        System.err.println(map3);

        Map<Integer, List<String>> map4 = list.stream().collect(Collectors.groupingBy(People::getId,
                Collectors.mapping(People::getName, Collectors.toList())));
        System.err.println(map4);

        Map<Boolean, List<People>> map5 = list.stream().collect(Collectors.groupingBy(p -> p.id > 1));
        System.err.println(map5);
    }

    @Test
    public void partitioningBy() {
        Map<Boolean, List<People>> map = list.stream().collect(
                Collectors.partitioningBy(p -> p.id > 1) //只接受返回值是 boolean 的 lambda, 是特殊的 groupingBy
        );
        System.err.println(map);
    }

    @Test
    public void customCollector() {
        Collector<People, StringJoiner, String> collector =
                Collector.of(
                        () -> new StringJoiner(" | "), // supplier
                        (j, p) -> j.add(p.name.toUpperCase()),  // accumulator, 累加器
                        (j1, j2) -> j1.merge(j2),               // combiner, 组合器
                        StringJoiner::toString);                // finisher

        String names = list.stream().collect(collector);

        System.out.println(names);
    }
}
